/*################################################################
# TRABAJO PRACTICO Nº2                                           #
# EJERCICIO 5                                                    #
# Primera reentrega                                              #
# ALUMNOS                                                        #
# Alonso, Rodolfo                            DNI: 33.474.354     #
# Barrera, Lourdes                           DNI: 33.306.634     #
# Gomez, Ezequiel                            DNI: 35.274.172     #
# Mahiques, Pablo                            DNI: 33.834.348     #
# Sanchez, Martín                            DNI:                #
################################################################*/

extern "C"
{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h> 
    #include <fcntl.h>
    #include <signal.h>
}

#include "eje5_comun.h"

#define N_CLIENTES 2

void comprobar_argumentos(const int argc, const char** argv);
void esperar_clientes();
int enviar_numero(const int numero, const int fifo_proceso);
void salir (int exit_code);
void handler (int);


PID_FIFO servidor = {};
PID_FIFO clientes[N_CLIENTES] = {};


int main(const int argc, const char** argv)
{
    comprobar_argumentos(argc, argv);

    for(int sig=1; sig<32; sig++) signal(sig, SIG_IGN);
    if (signal(SIGTERM, handler) == SIG_ERR)
    {
        printf("Error al instalar manejador de senial SIGTERM");
        exit(1);
    }

    //Abrimos el FIFO para recibir las conexiones de los clientes
    strcpy(servidor.nombre_fifo, argv[1]);
    servidor.pid  = getpid();
    servidor.fifo = abrir_fifo(servidor.nombre_fifo, 0666, O_RDWR, 1);

    //Esperamos la conexion de los clientes, luego de la cual tendremos sus pids ordenados
    esperar_clientes();

    //Bucle principal
    for(;;)
    {
        int numero;
        printf("Ingrese un numero: ");
        scanf("%d", &numero);

        if( enviar_numero(numero, clientes[numero%2].fifo) != 0 )
        {
            //Salimos del bucle si se produce un error al enviar
            break;
        }
    }

    //Nunca se debería terminar por aquí (a no ser que haya errores)
    salir(-100);
}


void comprobar_argumentos(const int argc, const char** argv)
{
    if (argc != 2)
    {
       printf("Error en la invocacion.\nUso: %s NOMBREFIFO\n", argv[0]);
       exit(-1);
    }
}


void esperar_clientes()
{
    printf("Esperando conexion de los clientes\n");

    //Esperamos la conexion de todos los clientes
    for(int i=0; i<N_CLIENTES; i++)
    {
        MENSAJE msg;
        
        if( leer_mensaje(servidor.fifo, &msg) != 0 )
        {
           printf("Error esperando conexiones de clientes\n");
           exit(-2);
        }

        clientes[i].pid  = msg.dato;
        strcpy(clientes[i].nombre_fifo, nombre_fifo_cliente(clientes[i].pid));
        clientes[i].fifo = abrir_fifo(clientes[i].nombre_fifo, 0666, O_RDWR, 0);

        printf("Se conecto el cliente con PID [%d]\n", clientes[i].pid);

        //Informamos al cliente nuestro PID
        MENSAJE msg_pidsrv = {servidor.pid};

        //Salida por FIFO
        if( write(clientes[i].fifo, &msg_pidsrv, sizeof(msg_pidsrv)) < 0 )
        {
            salir(-5);
        }
    }

    //Ordenamos los clientes por PID
    //TODO - Para N_CLIENTES distinto de 2 debe ordenarse el vector
    if( clientes[0].pid > clientes[1].pid)
    {
        const PID_FIFO aux = clientes[0];
        clientes[0] = clientes[1];
        clientes[1] = aux;
    }
}


int enviar_numero(const int numero, const int fifo_proceso)
{
    printf("Enviando numero [%d]\n", numero);

    MENSAJE msg = {numero};

    //Salida por FIFO
    if( write(fifo_proceso, &msg, sizeof(msg)) < 0 )
        return -1;

    return 0;
}


void salir (int exit_code)
{
    for(int i=0; i<N_CLIENTES; i++)
    {
        cerrar_fifo(clientes[i].fifo, clientes[i].nombre_fifo);
        clientes[i].fifo = 0;
        clientes[i].nombre_fifo[0] = '\0';

        kill(clientes[i].pid, SIGTERM);
        clientes[i].pid = 0;
    }

    cerrar_fifo(servidor.fifo, servidor.nombre_fifo);
    servidor.fifo = 0;
    servidor.nombre_fifo[0] = '\0';

    exit(exit_code);
}


void handler (int signum)
{
    if(signum == SIGTERM)
    {
        salir(0);
    }
}
